#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>

#include "terminals.h"
#include "list.h"

static void casperd_init();

list* jobs;
terminal_t* daemon_terminal;

char buffer[4096];

void launcher_sighandler(int sig) {
	int status = 0, pid;

	pid = wait(&status);
	pid = (int) list_remove_key(jobs, pid);

	sprintf(buffer, "jobs %d finished %d\n", pid, status);
	terminal_write_to_daemon(daemon_terminal, buffer);
}

int launcher_task() {
	int bytes_read = 0;
	pid_t child;
	char *ptr1, *ptr2, *cmd;

	buffer[255] = 0;

	char integer[12] = {0,0,0,0,0,0,0,0,0,0,0,0};
	int job_id;

	casperd_init();

	// Do something
	//while ((bytes_read = read(STDIN_FILENO, buffer, 255)) > 0) {
	while ((cmd = terminal_read_from_daemon(daemon_terminal)) != NULL) {
		if (!strncmp(cmd, "variable ", 9)) {
			fprintf(stderr, "DEBUG: launcher: received variable command \"%s\"\n", cmd);
			ptr1 = cmd + strlen(cmd);
			do {
				switch (*ptr1) {
					case ' ':
					case '\t':
					case '\0':
					case '\n':
					case '\r':
						*ptr1 = 0;
						break;
				}
				ptr1--;
			} while (ptr1[1] != 0);
			//fprintf(stderr, "DEBUG: launcher: normalized to \"%s\"\n", buffer);
			ptr1 = cmd + 9;
			ptr2 = strchr(ptr1, ' ');
			if (ptr2 == NULL) {
				fprintf(stderr, "DEBUG: launcher: deleting variable %s\n", ptr1);
				unsetenv(ptr1);
			}
			else {
				ptr2[0] = 0;
				ptr2++;
				fprintf(stderr, "DEBUG: launcher: setting variable %s to %s\n", ptr1, ptr2);
				setenv(ptr1, ptr2, 1);
			}
			free(cmd);
			continue;
		}


		if (strncmp(cmd, "launch ", 7)) {
			free(cmd);
			continue;
		}

		sscanf(&cmd[7], "%d", &job_id);

		child = fork();
		if (child < 0) {
			fprintf(stderr, "ERROR: launcher: unable to start job %s\n", cmd);
			write (STDOUT_FILENO, "error jobs start", 17);
			free(cmd);
			continue;
		}
		else if (child == 0) {
			sprintf(integer, "%d", job_id);
			fprintf(stderr, "INFO: launcher: starting job %s (ID: %d)...\n", &cmd[7+strlen(integer)+1], job_id);

			// This is the child...
			close (STDIN_FILENO);

			// Launch the job
			sprintf(buffer, "%s/scripts/casper-launch-job.sh", getenv("CASPER_ROOT_DIR"));
			execl(buffer, "casper-launch-job.sh", &cmd[7+strlen(integer)+1], integer, NULL);
		}
		else {
			// Aggiungere job_id e child ad una lista per sapere
			// quando un job è terminato
			list_add(jobs, (void*) job_id, child);
			free(cmd);
		}
	}

	fprintf(stderr, "INFO: launcher: exiting...\n");

	return EXIT_SUCCESS;
}

void casperd_init() {
	pid_t child;
	int res;

	child = fork();
	if (child < 0) {
		fprintf(stderr, "ERROR: launcher: unable to fork for init job\n");
		return;
	}
	else if (child == 0) {
		sprintf(buffer, "%s/scripts/casper-init.sh", getenv("CASPER_ROOT_DIR"));
		execl(buffer, "casper-init.sh", NULL);
	}
	else {
		wait(&res);
		fprintf(stderr, "INFO: launcher: init script ended with exit code %d\n", res);
		// Setting SIGCHLD handler
		signal(SIGCHLD, launcher_sighandler);
	}
}

int prepare_launcher(terminal_t* launcher_daemon_terminal) {
	int s_id;

	umask(0);

	s_id = setsid();
	if (s_id < 0) {
		fprintf(stderr, "ERROR: daemon: unable to get SID\n");
		return EXIT_FAILURE;
	}

	// Changing Working Directory
	if (chdir(getenv("CASPER_ROOT_DIR")) < 0) {
		fprintf(stderr, "ERROR: daemon: unable to chdir to /\n");
		return EXIT_FAILURE;
	}

	// Setting files
	if (dup2(launcher_daemon_terminal->pins.terminal_write, STDOUT_FILENO) < 0) {
		fprintf(stderr, "ERROR: launcher: unable to redirect STDOUT -> daemon commands pipe\n");
		return EXIT_FAILURE;
	}
	if (dup2(launcher_daemon_terminal->pins.terminal_read, STDIN_FILENO) < 0) {
		fprintf(stderr, "ERROR: launcher: unable to redirect STDIN -> daemon commands pipe\n");
		return EXIT_FAILURE;
	}
	close(launcher_daemon_terminal->pins.daemon_read);
	close(launcher_daemon_terminal->pins.daemon_write);

	jobs = list_new();
	daemon_terminal = launcher_daemon_terminal;

	return EXIT_SUCCESS;
}
